package com.foton.bpc.all.register.cluster;

import com.foton.bpc.all.config.RefrenceConfig;
import com.foton.bpc.all.config.RegisterConfig;
import com.foton.bpc.all.register.NotifyListener;
import com.foton.bpc.all.register.Register;
import com.foton.bpc.all.register.cluster.loadbalance.LoadBalance;
import com.foton.bpc.all.register.cluster.loadbalance.impl.RandomLoadBalance;
import com.foton.bpc.all.remoting.dto.BpcInvacation;
import com.foton.bpc.all.remoting.invoker.Invoker;
import com.foton.bpc.all.remoting.rpc.Protocol;
import com.foton.bpc.all.util.SpIUtils;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Author RenPu
 * @Date 2023/6/13 15:24
 * @Version 1.0
 * @Description:注册中心集群 处理类
 **/

@Slf4j
public class ClusterInvoker implements Invoker {

    //代表这个服务，能够调用得所有实例（服务实例缓存容器）
    public  Map<URI,Invoker> invokers=new ConcurrentHashMap();
    RefrenceConfig refrenceConfig;

    LoadBalance loadBalance;


    public ClusterInvoker(RefrenceConfig refrenceConfig) throws URISyntaxException {

        this.refrenceConfig=refrenceConfig;
        this.loadBalance=(LoadBalance)SpIUtils.getServiceImpl
                (refrenceConfig.getLoadBalance(),LoadBalance.class);

        //获取registerconfig以及类全类名
        String serviceName = refrenceConfig.getService().getName();

        //遍历处理registerconfig实例，
        List<RegisterConfig> registerConfigs = refrenceConfig.getRegisterConfigs();
        for (RegisterConfig registerConfig : registerConfigs) {

            //构建URI对象获取scheml,通过SPI机制获取对应得实现
            URI uri = new URI(registerConfig.getAddress());
            Register register=(Register) SpIUtils.getServiceImpl(uri.getScheme(), Register.class);

            //进行init操作以及订阅key值
            register.init(uri);
//            register.register(uri);
            register.subscribe(serviceName, new NotifyListener() {

                @Override
                public void notify(Set<URI> uriSet) {

                      //当服务存在【新增】，【新增】得操作触发此方法

                    //剔除 遍历当前缓存实例invokers,与最新实例set进行检验
                    for(URI uri : invokers.keySet()){
                        log.info("当前得服务Invoker信息：：："+invokers);
                         if(!uriSet.contains(uri)){
                             //更新缓存
                             invokers.remove(uri);
                         }
                    }


                      //新增，遍历当前最新得实例set,与缓存进行检验
                    for (URI uri1 : uriSet) {
                        if(!invokers.containsKey(uri1)){
                            //通过SPI机制，根据协议名称进行获取
                            Protocol protocol=(Protocol)SpIUtils.getServiceImpl(uri1.getScheme(), Protocol.class);
                            //服务调用所需得方法（服务调用者）   invoker代表一个长连接
                            Invoker invoker = protocol.refer(uri1);
                            invokers.putIfAbsent(uri1,invoker);
                        }

                    }
                }
            });
        }
    }


    /**
     *
     * @return
     */
    @Override
    public Class<?> getInterface() {
        return refrenceConfig.getService();
    }

    /**
     *
     * @param bpcInvacation
     * @return
     * @throws Exception
     */
    @Override
    public Object invoker(BpcInvacation bpcInvacation) throws Exception {

//        //这么多个invoker 应该如何选择 引入负责均衡   直接调用
//        Invoker invoker = new RandomLoadBalance().select(invokers);
//        Object result = invoker.invoker(bpcInvacation);


        //解析注解负载均衡得配置，集合SPI进行选择对应得实现方式
        Invoker invoker1 = loadBalance.select(invokers);
        Object result = invoker1.invoker(bpcInvacation);
        return result;
    }
}
